#pragma once

#include <iostream>
#include <string>
#include <cassert>
#include <filesystem>
#include <functional>
#include <cmath>
#include <unistd.h>
#include <stdexcept>

namespace test_common
{

// 简单的测试框架
class TestRunner
{
  public:
    static TestRunner& getInstance()
    {
        static TestRunner instance;
        return instance;
    }

    void runTest(const std::string& testName, std::function<void()> testFunc)
    {
        try {
            testFunc();
            passedTests_++;
            std::cout << "[PASS] " << testName << std::endl;
        } catch (const std::exception& e) {
            failedTests_++;
            std::cerr << "[FAIL] " << testName << ": " << e.what() << std::endl;
        } catch (...) {
            failedTests_++;
            std::cerr << "[FAIL] " << testName << ": Unknown exception" << std::endl;
        }
        totalTests_++;
    }

    int getPassed() const { return passedTests_; }
    int getFailed() const { return failedTests_; }
    int getTotal() const { return totalTests_; }

    void reset()
    {
        passedTests_ = 0;
        failedTests_ = 0;
        totalTests_ = 0;
    }

  private:
    int passedTests_ = 0;
    int failedTests_ = 0;
    int totalTests_ = 0;
};

// 断言宏
#define ASSERT_TRUE(condition) \
    do { \
        if (!(condition)) { \
            throw std::runtime_error("Assertion failed: " #condition " at " + \
                                    std::string(__FILE__) + ":" + std::to_string(__LINE__)); \
        } \
    } while (0)

#define ASSERT_FALSE(condition) ASSERT_TRUE(!(condition))

#define ASSERT_EQ(expected, actual) \
    do { \
        if ((expected) != (actual)) { \
            throw std::runtime_error("Assertion failed: expected " + \
                                    std::to_string(expected) + ", got " + \
                                    std::to_string(actual) + " at " + \
                                    std::string(__FILE__) + ":" + std::to_string(__LINE__)); \
        } \
    } while (0)

#define ASSERT_STREQ(expected, actual) \
    do { \
        if (std::string(expected) != std::string(actual)) { \
            throw std::runtime_error("Assertion failed: expected \"" + \
                                    std::string(expected) + "\", got \"" + \
                                    std::string(actual) + "\" at " + \
                                    std::string(__FILE__) + ":" + std::to_string(__LINE__)); \
        } \
    } while (0)

#define ASSERT_NEAR(expected, actual, tolerance) \
    do { \
        double diff = std::abs((expected) - (actual)); \
        if (diff > (tolerance)) { \
            throw std::runtime_error("Assertion failed: expected " + \
                                    std::to_string(expected) + ", got " + \
                                    std::to_string(actual) + " (diff: " + \
                                    std::to_string(diff) + ") at " + \
                                    std::string(__FILE__) + ":" + std::to_string(__LINE__)); \
        } \
    } while (0)

// 测试辅助函数
inline std::string getTestTempDir()
{
    namespace fs = std::filesystem;
    std::string tempDir = "/tmp/tools_test_" + std::to_string(getpid());
    fs::create_directories(tempDir);
    return tempDir;
}

inline void cleanupTestDir(const std::string& dir)
{
    namespace fs = std::filesystem;
    if (fs::exists(dir)) {
        fs::remove_all(dir);
    }
}

}  // namespace test_common

